package model

import (
	"github.com/zeromicro/go-zero/core/stores/mon"
	"go.mongodb.org/mongo-driver/mongo/options"
)
import "context"
import "go.mongodb.org/mongo-driver/bson"

var _ UserModel = (*customUserModel)(nil)

type (
	// UserModel is an interface to be customized, add more methods here,
	// and implement the added methods in customUserModel.
	UserModel interface {
		userModel
		FindOneByEmail(ctx context.Context, email string) (*User, error)
		FindByEmail(ctx context.Context, email string) ([]*User, error)
		FindOneByEmailAndInstallationId(ctx context.Context, email string, installationid int64) (*User, error)
		FindByEmailPage(ctx context.Context, email string, offset, limit int64) ([]*User, int64, error)
		FindByInstallIdPage(ctx context.Context, param User, offset, limit int64) ([]*User, int64, error)
		FindByInstallIdList(ctx context.Context, param User) ([]*User, error)
	}

	customUserModel struct {
		*defaultUserModel
	}
)

// NewUserModel returns a model for the mongo.
func NewUserModel(url, db, collection string) UserModel {
	conn := mon.MustNewModel(url, db, collection)
	return &customUserModel{
		defaultUserModel: newDefaultUserModel(conn),
	}
}

func (m *customUserModel) FindOneByEmail(ctx context.Context, email string) (*User, error) {

	var data User

	err := m.conn.FindOne(ctx, &data, bson.M{"email": email})
	switch err {
	case nil:
		return &data, nil
	case mon.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *customUserModel) FindByEmail(ctx context.Context, email string) ([]*User, error) {

	var data []*User

	err := m.conn.Find(ctx, &data, bson.M{"email": email})
	switch err {
	case nil:
		return data, nil
	case mon.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *customUserModel) FindOneByEmailAndInstallationId(ctx context.Context, email string, installationid int64) (*User, error) {

	var data User

	err := m.conn.FindOne(ctx, &data, bson.M{"email": email, "installation_id": installationid})
	switch err {
	case nil:
		return &data, nil
	case mon.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *customUserModel) FindByEmailPage(ctx context.Context, email string, offset, limit int64) ([]*User, int64, error) {
	var data []*User

	options := &options.FindOptions{
		Skip:  &offset,
		Limit: &limit,
		Sort:  bson.D{{"created_at", 1}},
	}
	count, _ := m.conn.CountDocuments(ctx, bson.M{"email": email})
	err := m.conn.Find(ctx, &data, bson.M{"email": email}, options)
	switch err {
	case nil:
		return data, count, nil
	case mon.ErrNotFound:
		return nil, 0, ErrNotFound
	default:
		return nil, 0, err
	}
}

func (m *customUserModel) FindByInstallIdPage(ctx context.Context, param User, offset, limit int64) ([]*User, int64, error) {
	var data []*User

	options := &options.FindOptions{
		Skip:  &offset,
		Limit: &limit,
		Sort:  bson.D{{"created_at", 1}},
	}
	count, _ := m.conn.CountDocuments(ctx, bson.M{"installation_id": param.InstallationId})
	err := m.conn.Find(ctx, &data, bson.M{"installation_id": param.InstallationId}, options)
	switch err {
	case nil:
		return data, count, nil
	case mon.ErrNotFound:
		return nil, 0, ErrNotFound
	default:
		return nil, 0, err
	}
}

func (m *customUserModel) FindByInstallIdList(ctx context.Context, param User) ([]*User, error) {
	var data []*User

	options := &options.FindOptions{
		Sort: bson.D{{"created_at", 1}},
	}
	err := m.conn.Find(ctx, &data, bson.M{"installation_id": param.InstallationId}, options)
	switch err {
	case nil:
		return data, nil
	case mon.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}
